#include "cfgparser_cli.h"

#include "cfgparser.h"
#include "cfgparser_storage_path.h"

#include <algorithm>
#include <cctype>
#include <cstdint>
#include <cstring>
#include <filesystem>
#include <iomanip>
#include <iostream>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>

namespace cfgparser::cli
{
    namespace
    {
        struct ParsedArgs
        {
            bool help{false};
            std::string config_path;
            std::vector<std::string> positionals;
            std::vector<std::string> warnings;
            std::optional<std::string> error;
        };

        std::string get_default_config_path()
        {
            try
            {
                return cfgparser::default_parser.get_config_file_path();
            }
            catch (const std::exception &)
            {
                try
                {
                    auto app_name = cfgparser::get_app_name();
                    if (app_name.empty())
                    {
                        app_name = "cfgparser";
                    }
                    return cfgparser::get_default_config_path(app_name) + "/config.bin";
                }
                catch (const std::exception &)
                {
                    return "config.bin";
                }
            }
        }

        ParsedArgs parse_args(int argc, char *argv[])
        {
            ParsedArgs result;
            result.config_path = get_default_config_path();

            bool expect_config_value = false;
            for (int i = 1; i < argc; ++i)
            {
                std::string arg(argv[i]);

                if (expect_config_value)
                {
                    if (arg.empty())
                    {
                        result.error = "--config 选项需要一个有效的路径";
                        return result;
                    }
                    result.config_path = arg;
                    expect_config_value = false;
                    continue;
                }

                if (arg == "-h" || arg == "--help")
                {
                    result.help = true;
                    continue;
                }
                if (arg == "-c" || arg == "--config")
                {
                    expect_config_value = true;
                    continue;
                }
                if (arg.rfind("--config=", 0) == 0)
                {
                    result.config_path = arg.substr(std::string("--config=").size());
                    if (result.config_path.empty())
                    {
                        result.error = "--config 选项需要一个有效的路径";
                    }
                    continue;
                }

                if (!arg.empty() && arg[0] == '-')
                {
                    result.warnings.emplace_back("忽略未知选项: " + arg);
                    continue;
                }

                result.positionals.emplace_back(std::move(arg));
            }

            if (expect_config_value)
            {
                result.error = "--config 选项需要一个参数";
            }

            return result;
        }

        void print_usage(const char *exe_name, const std::string &default_path)
        {
            std::cout << "用法: " << exe_name << " [选项] <命令> [参数...]" << std::endl;
            std::cout << std::endl;
            std::cout << "常用选项:" << std::endl;
            std::cout << "  -h, --help           显示帮助信息" << std::endl;
            std::cout << "  -c, --config <路径>  指定配置文件 (默认: " << default_path << ")" << std::endl;
            std::cout << std::endl;
            std::cout << "可用命令:" << std::endl;
            std::cout << "  list                 列出所有键值对" << std::endl;
            std::cout << "  get <key> [格式]     获取指定键的值 (格式: auto/string/int/float/hex)" << std::endl;
            std::cout << "  set <key> <value>    设置键的值 (value 保持原样写入)" << std::endl;
            std::cout << "  remove <key>         删除指定键" << std::endl;
            std::cout << "  clear                清空所有键" << std::endl;
        }

        enum class ValueFormat
        {
            AutoString,
            String,
            Integer,
            Float,
            Hex
        };

        std::optional<ValueFormat> parse_value_format(const std::string &token)
        {
            if (token.empty())
            {
                return ValueFormat::AutoString;
            }

            std::string lower = token;
            std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c)
                           { return static_cast<char>(std::tolower(c)); });

            if (lower == "auto")
            {
                return ValueFormat::AutoString;
            }
            if (lower == "s" || lower == "str" || lower == "string")
            {
                return ValueFormat::String;
            }
            if (lower == "i" || lower == "int" || lower == "integer")
            {
                return ValueFormat::Integer;
            }
            if (lower == "f" || lower == "float" || lower == "double")
            {
                return ValueFormat::Float;
            }
            if (lower == "h" || lower == "hex")
            {
                return ValueFormat::Hex;
            }

            return std::nullopt;
        }

        bool is_printable_ascii(const std::vector<uint8_t> &data)
        {
            return std::all_of(data.begin(), data.end(), [](uint8_t ch)
                               { return ch == '\n' || ch == '\r' || ch == '\t' || (ch >= 32 && ch <= 126); });
        }

        std::string bytes_to_ascii(const std::vector<uint8_t> &data)
        {
            return std::string(data.begin(), data.end());
        }

        std::string bytes_to_hex(const std::vector<uint8_t> &data)
        {
            std::ostringstream oss;
            oss << std::hex << std::setfill('0');
            for (uint8_t byte : data)
            {
                oss << std::setw(2) << static_cast<int>(byte);
            }
            return oss.str();
        }

        template <typename T>
        T read_little_endian(const std::vector<uint8_t> &data)
        {
            T value{};
            std::memcpy(&value, data.data(), sizeof(T));
            return value;
        }

        std::optional<long long> bytes_to_integer(const std::vector<uint8_t> &data)
        {
            if (data.empty())
            {
                return 0LL;
            }

            if (is_printable_ascii(data))
            {
                try
                {
                    std::string text = bytes_to_ascii(data);
                    size_t idx = 0;
                    long long value = std::stoll(text, &idx, 0);
                    if (idx != text.size())
                    {
                        return std::nullopt;
                    }
                    return value;
                }
                catch (...)
                {
                    return std::nullopt;
                }
            }

            switch (data.size())
            {
            case sizeof(int8_t):
                return static_cast<long long>(read_little_endian<int8_t>(data));
            case sizeof(int16_t):
                return static_cast<long long>(read_little_endian<int16_t>(data));
            case sizeof(int32_t):
                return static_cast<long long>(read_little_endian<int32_t>(data));
            case sizeof(int64_t):
                return static_cast<long long>(read_little_endian<int64_t>(data));
            default:
                return std::nullopt;
            }
        }

        std::optional<double> bytes_to_float(const std::vector<uint8_t> &data)
        {
            if (data.empty())
            {
                return 0.0;
            }

            if (is_printable_ascii(data))
            {
                try
                {
                    std::string text = bytes_to_ascii(data);
                    size_t idx = 0;
                    double value = std::stod(text, &idx);
                    if (idx != text.size())
                    {
                        return std::nullopt;
                    }
                    return value;
                }
                catch (...)
                {
                    return std::nullopt;
                }
            }

            if (data.size() == sizeof(float))
            {
                return static_cast<double>(read_little_endian<float>(data));
            }
            if (data.size() == sizeof(double))
            {
                return read_little_endian<double>(data);
            }
            return std::nullopt;
        }

        bool load_if_exists(cfgparser::CFGParser &parser, const std::string &path)
        {
            if (path.empty())
            {
                return false;
            }

            std::filesystem::path file_path(path);
            if (std::filesystem::exists(file_path))
            {
                return parser.load();
            }
            return true;
        }

        bool save_parser(cfgparser::CFGParser &parser, const std::string &path)
        {
            if (parser.save())
            {
                std::cout << "已保存到: " << path << std::endl;
                return true;
            }
            std::cerr << "保存配置文件失败: " << path << std::endl;
            return false;
        }
    } // namespace

    int run(int argc, char *argv[])
    {
        ParsedArgs args = parse_args(argc, argv);
        const std::string default_path = get_default_config_path();

        if (args.error.has_value())
        {
            std::cerr << args.error.value() << std::endl;
            print_usage(argc > 0 ? argv[0] : "cfgparser_cli", default_path);
            return 1;
        }

        for (const auto &warning : args.warnings)
        {
            std::cerr << warning << std::endl;
        }

        if (args.help || args.positionals.empty())
        {
            print_usage(argc > 0 ? argv[0] : "cfgparser_cli", default_path);
            return args.help ? 0 : 1;
        }

        const std::string &command = args.positionals.front();
        cfgparser::CFGParser parser(args.config_path, cfgparser::CFGParserOptions{});

        if (!load_if_exists(parser, args.config_path))
        {
            std::cerr << "无法加载配置文件: " << args.config_path << std::endl;
            return 1;
        }

        if (command == "list")
        {
            auto entries = parser.enumerate();
            if (entries.empty())
            {
                std::cout << "配置为空。" << std::endl;
                return 0;
            }

            std::cout << "共 " << entries.size() << " 条记录:" << std::endl;
            for (const auto &entry : entries)
            {
                const auto &key_bytes = entry.first;
                const auto &value_bytes = entry.second;

                std::cout << "- key: ";
                if (is_printable_ascii(key_bytes))
                {
                    std::cout << '"' << bytes_to_ascii(key_bytes) << '"';
                }
                else
                {
                    std::cout << "0x" << bytes_to_hex(key_bytes);
                }

                std::cout << " | value: ";
                if (is_printable_ascii(value_bytes))
                {
                    std::cout << '"' << bytes_to_ascii(value_bytes) << '"';
                }
                else
                {
                    std::cout << "0x" << bytes_to_hex(value_bytes);
                }
                std::cout << std::endl;
            }
            return 0;
        }

        if (command == "get")
        {
            if (args.positionals.size() < 2)
            {
                std::cerr << "用法: get <key> [auto|string|int|float|hex]" << std::endl;
                return 1;
            }

            const std::string &key = args.positionals[1];
            ValueFormat format = ValueFormat::AutoString;

            if (args.positionals.size() >= 3)
            {
                auto parsed = parse_value_format(args.positionals[2]);
                if (!parsed.has_value())
                {
                    std::cerr << "未知的格式: " << args.positionals[2] << std::endl;
                    return 1;
                }
                format = parsed.value();
            }

            if (!parser.contains(key))
            {
                std::cerr << "未找到键: " << key << std::endl;
                return 1;
            }

            auto raw_value = parser.get(key, std::vector<uint8_t>{});

            switch (format)
            {
            case ValueFormat::AutoString:
            case ValueFormat::String:
            {
                if (is_printable_ascii(raw_value))
                {
                    std::cout << bytes_to_ascii(raw_value) << std::endl;
                }
                else if (format == ValueFormat::AutoString)
                {
                    std::cout << "0x" << bytes_to_hex(raw_value) << std::endl;
                }
                else
                {
                    std::cerr << "值包含非可打印字符，无法按字符串显示。" << std::endl;
                    return 1;
                }
                return 0;
            }
            case ValueFormat::Integer:
            {
                auto number = bytes_to_integer(raw_value);
                if (!number.has_value())
                {
                    std::cerr << "无法将值转换为整数" << std::endl;
                    return 1;
                }
                std::cout << number.value() << std::endl;
                return 0;
            }
            case ValueFormat::Float:
            {
                auto real = bytes_to_float(raw_value);
                if (!real.has_value())
                {
                    std::cerr << "无法将值转换为小数" << std::endl;
                    return 1;
                }
                std::cout << real.value() << std::endl;
                return 0;
            }
            case ValueFormat::Hex:
            {
                std::cout << "0x" << bytes_to_hex(raw_value) << std::endl;
                return 0;
            }
            }
            return 0;
        }

        if (command == "set")
        {
            if (args.positionals.size() < 3)
            {
                std::cerr << "用法: set <key> <value>" << std::endl;
                return 1;
            }

            const std::string &key = args.positionals[1];
            std::string value = args.positionals[2];
            for (std::size_t i = 3; i < args.positionals.size(); ++i)
            {
                value.append(" ").append(args.positionals[i]);
            }

            parser.set(key, value);
            if (!save_parser(parser, args.config_path))
            {
                return 1;
            }
            return 0;
        }

        if (command == "remove")
        {
            if (args.positionals.size() < 2)
            {
                std::cerr << "用法: remove <key>" << std::endl;
                return 1;
            }

            const std::string &key = args.positionals[1];
            if (!parser.contains(key))
            {
                std::cerr << "未找到键: " << key << std::endl;
                return 1;
            }

            parser.remove(key);
            if (!save_parser(parser, args.config_path))
            {
                return 1;
            }
            return 0;
        }

        if (command == "clear")
        {
            parser.clear();
            if (!save_parser(parser, args.config_path))
            {
                return 1;
            }
            return 0;
        }

        std::cerr << "未知命令: " << command << std::endl;
        print_usage(argc > 0 ? argv[0] : "cfgparser_cli", default_path);
        return 1;
    }

} // namespace cfgparser::cli
